package edu.ubb.remeye.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JRadioButton;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;

import edu.ubb.remeye.client.settings.ClientRuntimeSettings;
import edu.ubb.remeye.client.settings.ClientSetter;
import edu.ubb.remeye.control.Control;
import edu.ubb.remeye.encodings.EncodingType;
import edu.ubb.remeye.gui.internationalization.LanguageManager;
import edu.ubb.remeye.gui.internationalization.languages.Languages;
import edu.ubb.remeye.security.SecurityType;
import edu.ubb.remeye.server.settings.ServerRuntimeSettings;
import edu.ubb.remeye.server.settings.ServerSetter;

/**
 * Main frame class of application.
 * 
 * @author Andrew Ianicicau
 *
 */
public class MainFrame extends JFrame implements ActionListener {

	///////////////////////////////////////////////////////////////////////////////////
	////		ATTRIBUTES - MainFrame
	///////////////////////////////////////////////////////////////////////////////////

	private static final long serialVersionUID = 1L;
	
	/**
	 * Instance of class for singleton design pattern.
	 */
	private static MainFrame mainFrame;
	
	/**
	 * Menu bar.
	 */
	private JMenuBar menuBar;
	
	/**
	 * File menu.
	 */
	private JMenu fileMenu;
	private JMenuItem exit;
	
	/**
	 * Server menu.
	 */
	private JMenu serverMenu;
	private JMenu serverSettings;
	private JPanel serverConnectionPanel;
	private JLabel serverPortLabel;
	private JTextField serverPort;
	private JLabel serverPasswordLabel;
	private JPasswordField serverPassword;
	private JPanel serverSecurityPanel;
	private JCheckBox[] availableSecurityTypes;
	private JPanel serverEncodingPanel;
	private JCheckBox[] availableEncodingTypes;
	private JMenuItem startServer;
	private JMenuItem stopServer;
	
	/**
	 * Client menu.
	 */
	private JMenu clientMenu;
	private JMenu clientSettings;
	private JPanel clientConnectionPanel;
	private JLabel clientIpLabel;
	private JTextField clientIp;
	private JLabel clientPortLabel;
	private JTextField clientPort;
	private JCheckBox getControl;
	private JLabel clientPasswordLabel;
	private JPasswordField clientPassword;
	private JPanel clientSecurityPanel;
	private ButtonGroup securityGroup;
	private JRadioButton[] securityType;
	private JPanel clientEncodingPanel;
	private ButtonGroup encodingGroup;
	private JRadioButton[] encodingType;
	private JMenuItem connectClient;
	private JMenuItem disconnectClient;
	
	/**
	 * Language menu.
	 */
	private JMenu languageMenu;
	private ButtonGroup languageGroup;
	private JRadioButtonMenuItem[] languages;
	
	/**
	 * Locales according to languages.
	 */
	private Locale[] locales;
	
	/**
	 * Frame's content pane.
	 */
	private JPanel base;
	
	/**
	 * Image panel for drawing.
	 */
	private ImagePanel imagePanel;
	
	/**
	 * Scroll for image panel.
	 */
	private JScrollPane scroll;
	
	/**
	 * Language manager for internationalization.
	 */
	private LanguageManager languageManager;
	
	/**
	 * Location of country flags associated to languages.
	 */
	private static final String IMAGE_FLAGS_PATH = "resources/flags/";
	
	/**
	 * Location of menu images.
	 */
	private static final String IMAGES_PATH = "resources/";

	
	
	///////////////////////////////////////////////////////////////////////////////////
	////		CONSTRUCTORS - MainFrame
	///////////////////////////////////////////////////////////////////////////////////

	private MainFrame() {
		languageManager = LanguageManager.getLanguageManager();
		
		base = new JPanel();
		base.setLayout(new BorderLayout());
        
        menuBar = new JMenuBar();
        menuBar.setBackground(new Color(0, 138, 138));
        menuBar.setLayout(new FlowLayout(FlowLayout.CENTER, 30, 0));
        setJMenuBar(menuBar);
        
        fileMenu = new JMenu();
        fileMenu.setIcon(new ImageIcon(IMAGES_PATH + "file.png"));
        fileMenu.setForeground(Color.green);
        menuBar.add(fileMenu);
        
        exit = new JMenuItem();
        exit.setIcon(new ImageIcon(IMAGES_PATH + "exit.jpg"));
        exit.addActionListener(this);
        fileMenu.add(exit);
        
        serverMenu = new JMenu();
        serverMenu.setIcon(new ImageIcon(IMAGES_PATH + "server.png"));
        serverMenu.setForeground(Color.green);
        menuBar.add(serverMenu);
        
        serverSettings = new JMenu();
        serverSettings.setIcon(new ImageIcon(IMAGES_PATH + "serversettings.jpg"));
        serverMenu.add(serverSettings);
        
        serverConnectionPanel = new JPanel();
        serverConnectionPanel.setLayout(new GridLayout(0, 2, 3, 3));
        serverSettings.add(serverConnectionPanel);
        
        serverPortLabel = new JLabel("", JLabel.CENTER);
        serverConnectionPanel.add(serverPortLabel);
        
        serverPort = new JTextField(5);
        serverPort.setText(String.valueOf(ServerSetter.getInstance().getPort()));
        serverConnectionPanel.add(serverPort);
        
        serverPasswordLabel = new JLabel("", JLabel.CENTER);
        serverConnectionPanel.add(serverPasswordLabel);
        
        serverPassword = new JPasswordField(10);
        serverConnectionPanel.add(serverPassword);
        
        serverSecurityPanel = new JPanel();
        serverSecurityPanel.setLayout(new GridLayout(0, 1, 3, 3));
        serverSettings.add(serverSecurityPanel);
        
        availableSecurityTypes = getSecurityCheckBoxes();
        for(JCheckBox security : availableSecurityTypes) {
        	serverSecurityPanel.add(security);
        }
        
        serverEncodingPanel = new JPanel();
        serverEncodingPanel.setLayout(new GridLayout(0, 1, 3, 4));
        serverSettings.add(serverEncodingPanel);
        
        availableEncodingTypes = getEncodingCheckBoxes();
        for(JCheckBox encoding : availableEncodingTypes) {
        	serverEncodingPanel.add(encoding);
        }
        
        startServer = new JMenuItem();
        startServer.setIcon(new ImageIcon(IMAGES_PATH + "start.jpg"));
        startServer.addActionListener(this);
        serverMenu.add(startServer);
        
        stopServer = new JMenuItem();
        stopServer.setIcon(new ImageIcon(IMAGES_PATH + "stop.jpg"));
        stopServer.addActionListener(this);
        serverMenu.add(stopServer);
        
        startServer.setEnabled(true);
		stopServer.setEnabled(false);
        
        clientMenu = new JMenu();
        clientMenu.setIcon(new ImageIcon(IMAGES_PATH + "client.png"));
        clientMenu.setForeground(Color.green);
        menuBar.add(clientMenu);
        
        clientSettings = new JMenu();
        clientSettings.setIcon(new ImageIcon(IMAGES_PATH + "clientsettings.jpg"));
        clientMenu.add(clientSettings);
        
        clientConnectionPanel = new JPanel();
        clientConnectionPanel.setLayout(new GridLayout(0, 2, 3, 3));
        clientSettings.add(clientConnectionPanel);
        
        clientIpLabel = new JLabel("", JLabel.CENTER);
        clientConnectionPanel.add(clientIpLabel);
        
        clientIp = new JTextField(10);
        clientIp.setText(ClientSetter.getInstance().getIp());
        clientConnectionPanel.add(clientIp);
        
        clientPortLabel = new JLabel("", JLabel.CENTER);
        clientConnectionPanel.add(clientPortLabel);
        
        clientPort = new JTextField(5);
        clientPort.setText(String.valueOf(ClientSetter.getInstance().getPort()));
        clientConnectionPanel.add(clientPort);
        
        clientConnectionPanel.add(new JLabel());
        
        getControl = new JCheckBox();
        getControl.setSelected(ClientSetter.getInstance().getControl());
        clientConnectionPanel.add(getControl);
        
        clientPasswordLabel = new JLabel("", JLabel.CENTER);
        clientConnectionPanel.add(clientPasswordLabel);
        
        clientPassword = new JPasswordField(10);
        clientConnectionPanel.add(clientPassword);
        
        clientSecurityPanel = new JPanel();
        clientSecurityPanel.setLayout(new GridLayout(0, 1, 3, 3));
        clientSettings.add(clientSecurityPanel);
        
        securityGroup = new ButtonGroup();
        securityType = getSecurityRadioButtons(securityGroup);
        for(JRadioButton security : securityType) {
        	clientSecurityPanel.add(security);
        }
        
        clientEncodingPanel = new JPanel();
        clientEncodingPanel.setLayout(new GridLayout(0, 1, 3, 3));
        clientSettings.add(clientEncodingPanel);
        
        encodingGroup = new ButtonGroup();
        encodingType = getEncodingRadioButtons(encodingGroup);
        for(JRadioButton encoding : encodingType) {
        	clientEncodingPanel.add(encoding);
        }
        
        connectClient = new JMenuItem();
        connectClient.setIcon(new ImageIcon(IMAGES_PATH + "connect.jpg"));
        connectClient.addActionListener(this);
        clientMenu.add(connectClient);
        
        disconnectClient = new JMenuItem();
        disconnectClient.setIcon(new ImageIcon(IMAGES_PATH + "disconnect.jpg"));
        disconnectClient.addActionListener(this);
        clientMenu.add(disconnectClient);
        
        languageMenu = new JMenu();
        languageMenu.setIcon(new ImageIcon(IMAGES_PATH + "languages.png"));
        languageMenu.setForeground(Color.green);
        menuBar.add(languageMenu);
        
        locales = getLocales();
        
        languageGroup = new ButtonGroup();
        languages = new JRadioButtonMenuItem[locales.length];
        for(int i = 0; i < locales.length; i++) {
        	languages[i] = new JRadioButtonMenuItem(locales[i].getISO3Language(), new ImageIcon(IMAGE_FLAGS_PATH+locales[i].toString()+".jpg"));
        	languages[i].addActionListener(this);
        	languageMenu.add(languages[i]);
        	languageGroup.add(languages[i]);
        }
        
        languages[0].setSelected(true);
        
        setLabels(locales[0]);
        
        connectClient.setEnabled(true);
		disconnectClient.setEnabled(false);
		
		imagePanel = new ImagePanel(0, 0);
		base.add(imagePanel, BorderLayout.CENTER);
		
		setContentPane(base);
		setBounds(0, 0, 1024, 768);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        setTitle("RemEye");
        Image image = Toolkit.getDefaultToolkit().getImage(IMAGES_PATH + "logo.jpg");
        setIconImage(image);
	}

	
	
	///////////////////////////////////////////////////////////////////////////////////
	////		METHODS - MainFrame
	///////////////////////////////////////////////////////////////////////////////////
	
	/**
	 * Get instance of class object.
	 */
	public static MainFrame getInstance() {
		if(mainFrame == null)
			mainFrame = new MainFrame();
		return mainFrame;
	}
	
	/**
	 * Getting locales from available languages.
	 * @return Locales.
	 */
	private Locale[] getLocales() {
		Languages[] lang = Languages.getLanguages();
		Locale[] locales = new Locale[lang.length];
		for(int i = 0; i < lang.length; i++) {
			String[] language = lang[i].toString().split("_");
			locales[i] = new Locale(language[0], language[1]);
		}
		return locales;
	}
	
	/**
	 * Setting labels for menus and menu items.
	 * @param locale Locale to use.
	 */
	private void setLabels(Locale locale) {
		languageManager.setCurrentLocale(locale);
		
		fileMenu.setText(languageManager.getText("file"));
		exit.setText(languageManager.getText("exit"));
		serverMenu.setText(languageManager.getText("server"));
		serverSettings.setText(languageManager.getText("settings"));
		serverConnectionPanel.setBorder(BorderFactory.createTitledBorder(languageManager.getText("connection")));
		serverPortLabel.setText(languageManager.getText("port")+":");
		serverPasswordLabel.setText(languageManager.getText("password")+":");
		serverSecurityPanel.setBorder(BorderFactory.createTitledBorder(languageManager.getText("security")));
		serverEncodingPanel.setBorder(BorderFactory.createTitledBorder(languageManager.getText("imageencoding")));
		startServer.setText(languageManager.getText("start"));
		stopServer.setText(languageManager.getText("stop"));
		clientMenu.setText(languageManager.getText("client"));
		clientSettings.setText(languageManager.getText("settings"));
		clientConnectionPanel.setBorder(BorderFactory.createTitledBorder(languageManager.getText("connection")));
		clientIpLabel.setText(languageManager.getText("ip")+":");
		clientPortLabel.setText(languageManager.getText("port")+":");
		getControl.setText(languageManager.getText("controlserver"));
		clientPasswordLabel.setText(languageManager.getText("password")+":");
		clientSecurityPanel.setBorder(BorderFactory.createTitledBorder(languageManager.getText("security")));
		clientEncodingPanel.setBorder(BorderFactory.createTitledBorder(languageManager.getText("imageencoding")));
		connectClient.setText(languageManager.getText("connect"));
		disconnectClient.setText(languageManager.getText("disconnect"));
		languageMenu.setText(languageManager.getText("languages"));
	}
	
	public ImagePanel getImagePanel() {
		return imagePanel;
	}
	
	/**
	 * Show frame.
	 */
	public void showFrame() {
		mainFrame.setVisible(true);
	}
	
	/**
	 * Create checkboxes array of security types.
	 * @return Security type checkboxes array.
	 */
	private JCheckBox[] getSecurityCheckBoxes() {
		List<SecurityType> types = SecurityType.getSecurityTypeList();
		List<SecurityType> available = ServerSetter.getInstance().getSecurityTypes();
		JCheckBox[] list = new JCheckBox[types.size()];
		for(int i = 0; i < types.size(); i++) {	
			list[i] = new JCheckBox(types.get(i).name());
			if(available.contains(types.get(i))) {
				list[i].setSelected(true);
			}
		}
		return list;
	}
	
	/**
	 * Create checkboxes array of encoding types.
	 * @return Encoding type checkboxes array.
	 */
	private JCheckBox[] getEncodingCheckBoxes() {
		List<EncodingType> types = EncodingType.getEncodingTypeList();
		List<EncodingType> available = ServerSetter.getInstance().getEncodingTypes();
		JCheckBox[] list = new JCheckBox[types.size()];
		
		// BMP must be selected always and inaccessible
		list[0] = new JCheckBox(types.get(0).name());
		list[0].setSelected(true);
		list[0].setEnabled(false);
		
		for(int i = 1; i < types.size(); i++) {	
			list[i] = new JCheckBox(types.get(i).name());
			if(available.contains(types.get(i))) {
				list[i].setSelected(true);
			}
		}
		return list;
	}
	
	/**
	 * Create radio buttons array of security types.
	 * @param group Button group to add radio buttons.
	 * @return Array of security type radio buttons.
	 */
	private JRadioButton[] getSecurityRadioButtons(ButtonGroup group) {
		List<SecurityType> types = SecurityType.getSecurityTypeList();
		SecurityType selected = ClientSetter.getInstance().getDesiredSecurityType();
		JRadioButton[] list = new JRadioButton[types.size()];
		for(int i = 0; i < types.size(); i++) {
			list[i] = new JRadioButton(types.get(i).name());
			if(types.get(i).equals(selected))
				list[i].setSelected(true);
			group.add(list[i]);
		}
		return list;
	}
	
	/**
	 * Create radio buttons array of encoding types.
	 * @param group Button group to add radio buttons.
	 * @return Array of encoding type radio buttons.
	 */
	private JRadioButton[] getEncodingRadioButtons(ButtonGroup group) {
		List<EncodingType> types = EncodingType.getEncodingTypeList();
		EncodingType selected = ClientSetter.getInstance().getDesiredEncodingType();
		JRadioButton[] list = new JRadioButton[types.size()];
		for(int i = 0; i < types.size(); i++) {
			list[i] = new JRadioButton(types.get(i).name());
			if(types.get(i).equals(selected))
				list[i].setSelected(true);
			group.add(list[i]);
		}
		return list;
	}
	
	/**
	 * Draw image to image panel.
	 * @param image Image to draw.
	 */
	public void draw(BufferedImage image) {	
		// draw image
		imagePanel.drawDesktopImage(image);
		
		// add scroll
		if(scroll == null) {
			imagePanel.setPreferredSize(new Dimension(image.getWidth(), image.getHeight()));
			scroll = new JScrollPane(imagePanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
	        base.add(scroll);
	        this.validate();
		}
	}
	
	/**
	 * Save entered settings.
	 */
	private void saveServerSettings() {
		ServerSetter setter = ServerSetter.getInstance();
		setter.setPort(getPort(serverPort.getText()));
		ServerRuntimeSettings.getinstance().setServerPassword(new String(serverPassword.getPassword()));
		setter.setSecurityTypes(getSecurityTypes());
		setter.setEncodingTypes(getEncodingTypes());
	}
	
	/**
	 * Save client settings.
	 */
	private void saveClientSettings() {
		ClientSetter setter = ClientSetter.getInstance();
		setter.setIp(clientIp.getText());
		setter.setPort(getPort(clientPort.getText()));
		ClientRuntimeSettings.getInstance().setClientPassword(new String(clientPassword.getPassword()));
		setter.setControl(getControl.isSelected());
		setter.setDesiredSecurityType(getSelectedSecurity());
		setter.setDesiredEncodingType(getSelectedEncoding());
	}
	
	/**
	 * Get port from port text field.
	 * @param port Port string.
	 * @return Port number.
	 */
	private int getPort(String port) {
		try {
			int parsed = Integer.parseInt(port);
			return parsed;
		} catch(NumberFormatException e) {
			return 0;
		}
	}
	
	/**
	 * Get selected security types' list from checkboxes.
	 * @return Selected security types' list.
	 */
	private List<SecurityType> getSecurityTypes() {
		List<SecurityType> list = new ArrayList<SecurityType>();
		for(int i = 0; i < availableSecurityTypes.length; i++) {
			if(availableSecurityTypes[i].isSelected())
				list.add(SecurityType.valueOf(securityType[i].getText()));
		}
		return list;
	}
	
	/**
	 * Get selected encoding types' list from checkboxes.
	 * @return Selected encoding types' list.
	 */
	private List<EncodingType> getEncodingTypes() {
		List<EncodingType> list = new ArrayList<EncodingType>();
		for(int i = 0; i < availableEncodingTypes.length; i++) {
			if(availableEncodingTypes[i].isSelected())
				list.add(EncodingType.valueOf(encodingType[i].getText()));
		}
		return list;
	}
	
	/**
	 * Get selected security type from radio buttons group.
	 * @return Selected security type.
	 */
	private SecurityType getSelectedSecurity() {
		for(int i = 0; i < securityType.length; i++) {
			if(securityType[i].isSelected()) {
				return SecurityType.valueOf(securityType[i].getText());
			}
		}
		return SecurityType.INVALID;
	}
	
	/**
	 * Get selected encoding type from radio buttons group.
	 * @return Selected encoding type.
	 */
	private EncodingType getSelectedEncoding() {
		for(int i = 0; i < encodingType.length; i++) {
			if(encodingType[i].isSelected()) {
				return EncodingType.valueOf(encodingType[i].getText());
			}
		}
		return EncodingType.BMP;
	}

	@Override
	public void actionPerformed(ActionEvent event) {
		// exit menuitem selected
		if(event.getSource().equals(exit)) {
			System.exit(0);
		}
		
		// startServer menuitem selected
		if(event.getSource().equals(startServer)) {
			saveServerSettings();
			Control.startServer();
			startServer.setEnabled(false);
			stopServer.setEnabled(true);
		}
		
		// stopServer menuitem selected
		if(event.getSource().equals(stopServer)) {
			Control.stopServer();
			startServer.setEnabled(true);
			stopServer.setEnabled(false);
		}
		
		// connectClient menuitem selected
		if(event.getSource().equals(connectClient)) {
			saveClientSettings();
			Control.connectClient();
			connectClient.setEnabled(false);
			disconnectClient.setEnabled(true);
		}
		
		// disconnectClient menuitem selected
		if(event.getSource().equals(disconnectClient)) {
			Control.disconnectClient();
			connectClient.setEnabled(true);
			disconnectClient.setEnabled(false);
		}
		
		// if a language is selected from language radiobuttons
		for(int i = 0; i < languages.length; i++) {
			if(event.getSource().equals(languages[i])) {
				setLabels(locales[i]);
				break;
			}
		}
		
	}

}
